package com.cxx.purchasecharge.component.controller;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONArray;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.cxx.purchasecharge.component.bean.AccountingTypeBean;
import com.cxx.purchasecharge.component.bean.ActionResult;
import com.cxx.purchasecharge.component.bean.ActionResult.ActionResultStatus;
import com.cxx.purchasecharge.component.bean.DataGridRequestForm;
import com.cxx.purchasecharge.component.utils.AjaxUtils;
import com.cxx.purchasecharge.component.utils.BeanConvertUtils;
import com.cxx.purchasecharge.component.utils.ComponentConstants;
import com.cxx.purchasecharge.component.utils.MessageProperties;
import com.cxx.purchasecharge.core.model.AccountingModeCode;
import com.cxx.purchasecharge.core.model.persistence.Accounting;
import com.cxx.purchasecharge.core.model.persistence.AccountingType;
import com.cxx.purchasecharge.dal.AccountingDao;
import com.cxx.purchasecharge.dal.AccountingTypeDao;

@Controller
@RequestMapping ("/expenseType")
public class AccountingTypeManager
{
    private static final Logger logger = Logger.getLogger (AccountingTypeManager.class);

    @Autowired
    private AccountingTypeDao expenseTypeDao;
    @Autowired
    private AccountingDao expenseDao;

    @RequestMapping (value = "/")
    public String redirectToMainPage ()
    {
        return "accountingTypeManagement";
    }

    @RequestMapping (value = "/checkExist", method = RequestMethod.POST)
    public @ResponseBody
    String checkExist (@RequestParam String expenseTypeId, @RequestParam String name)
    {
        if (StringUtils.isBlank (expenseTypeId))
        {
            // new
            AccountingType obj = expenseTypeDao.findByName (name);
            if (null != obj)
            {
                return "false";
            }
        }
        else
        {
            // edit
            long id = Long.parseLong (expenseTypeId);
            AccountingType accountType = expenseTypeDao.findByName (name);
            if (null != accountType && accountType.getId () != id)
            {
                return "false";
            }
        }

        return "true";
    }

    @RequestMapping (value = "/getAllType", method = RequestMethod.POST)
    public @ResponseBody
    String getExpenseTypes (DataGridRequestForm dataGridRequestForm)
    {
        List <AccountingType> accountTypes = (List <AccountingType>) expenseTypeDao.getAll ();
        
        JSONArray jsonObject = JSONArray.fromObject (BeanConvertUtils.accountingTypeList2AccountingTypeBeanList (accountTypes));
        return jsonObject.toString ();
    }
    @RequestMapping (value = "/getTypeByMode", method = RequestMethod.POST)
    public @ResponseBody
    String getTypeByMode (HttpServletRequest request)
    {
        Object obj = request.getParameter("accountingMode");
        if (null != obj && StringUtils.isNotBlank(obj.toString()))
        {
            AccountingModeCode mode = AccountingModeCode.IN_COME.toString().equals(obj.toString()) ? AccountingModeCode.IN_COME
                : AccountingModeCode.OUT_LAY;
            List<AccountingType> accountTypes = (List<AccountingType>) expenseTypeDao.findByMode(mode);
            JSONArray jsonObject = JSONArray.fromObject(BeanConvertUtils.accountingTypeList2AccountingTypeBeanList(accountTypes));
            return jsonObject.toString();
        }
        else
        {
            logger.warn("accountingMode must not be empty");
            ActionResult ar = ActionResult.badRequest().withMessage("accountingMode must not be empty").build();
            return AjaxUtils.getJsonObject(ar);
        }
    }

    @RequestMapping (value = "/newExpenseType", method = RequestMethod.POST)
    public @ResponseBody
    String addExpenseType (AccountingTypeBean accountTypeBean, BindingResult result)
    {
        if (result.hasErrors ())
        {
            logger.error (result.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            AccountingType accountType = BeanConvertUtils.accountingTypeBean2AccountingType (accountTypeBean);
            ActionResult ar = ActionResult.createActionResult ().build ();

            try
            {
                expenseTypeDao.save (accountType);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }
            catch (Exception e)
            {
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_FAIL,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
                logger.error (e.getMessage (), e);
            }

            return AjaxUtils.getJsonObject (ar);
        }
    }

    @RequestMapping (value = "/updateExpenseType", method = RequestMethod.POST)
    public @ResponseBody
    String updateExpenseType (AccountingTypeBean accountTypeBean, BindingResult result)
    {
        if (result.hasErrors ())
        {
            logger.error (result.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            AccountingType accountType = BeanConvertUtils.accountingTypeBean2AccountingType (accountTypeBean);
            ActionResult ar = ActionResult.createActionResult ().build ();

            try
            {
                expenseTypeDao.save (accountType);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }

            return AjaxUtils.getJsonObject (ar);
        }
    }

    @RequestMapping (value = "/delExpenseType", method = RequestMethod.POST)
    public @ResponseBody
    String deleteExpenseType (@RequestParam String ids)
    {
        if (null != ids && ids.trim ().length () > 0)
        {
            List <AccountingType> expenseTypes = new ArrayList <AccountingType> ();
            AccountingType expenseType;
            if (ids.indexOf (";") != -1)
            {
                String[] idArr = ids.split (";");
                for (String typeId : idArr)
                {
                    expenseType = new AccountingType ();
                    long expenseTypeId = Long.parseLong (typeId);
                    expenseType.setId (expenseTypeId);
                    List <Accounting> expenses = expenseDao.findByType (expenseTypeId);
                    if (CollectionUtils.isEmpty (expenses))
                    {
                        expenseTypes.add (expenseType);
                    }
                }
            }
            else
            {
                expenseType = new AccountingType ();
                long expenseTypeId = Long.parseLong (ids);
                expenseType.setId (expenseTypeId);
                List <Accounting> expenses = expenseDao.findByType (expenseTypeId);
                if (CollectionUtils.isEmpty (expenses))
                {
                    expenseTypes.add (expenseType);
                }
            }

            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                expenseTypeDao.delete (expenseTypes);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }

            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            logger.error (ActionResultStatus.BAD_REQUEST + " ids=" + ids + " when delete expense type");
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
    }

    @RequestMapping (value = "/saveExpenseType", method = RequestMethod.POST)
    public @ResponseBody
    String saveExpenseType (@RequestParam String expenseTypes)
    {
        List <AccountingType> addOrEditList = new ArrayList <AccountingType> ();
        List <AccountingType> deleteList = new ArrayList <AccountingType> ();
        // List <ExpenseType> allList = new ArrayList <ExpenseType> ();
        if (StringUtils.isNotBlank (expenseTypes))
        {
            String[] expenseTypeArr = expenseTypes.split (";");
            if (expenseTypeArr.length > 0)
            {
                for (String expenseType : expenseTypeArr)
                {
                    if (StringUtils.isNotBlank (expenseType))
                    {
                        String[] itemArr = expenseType.split (",");
                        AccountingType et = new AccountingType ();
                        et.setId (StringUtils.isNotBlank (itemArr[0]) ? Long.parseLong (itemArr[0]) : 0);
                        et.setName (itemArr[1]);
                        et.setAccountingMode (AccountingModeCode.IN_COME.toString ().equals (itemArr[2]) ? AccountingModeCode.IN_COME : AccountingModeCode.OUT_LAY);
                        addOrEditList.add (et);
                    }
                }

                List <AccountingType> storedExpenseTypes = (List <AccountingType>) expenseTypeDao.findAll ();
                for (AccountingType storedET : storedExpenseTypes)
                {
                    boolean exist = false;
                    for (AccountingType et : addOrEditList)
                    {
                        if (storedET.getId () == et.getId ())
                        {
                            exist = true;
                            break;
                        }
                    }
                    if (!exist)
                    {
                        List <Accounting> expenses = expenseDao.findByType (storedET.getId ());
                        if (CollectionUtils.isEmpty (expenses))
                        {
                            deleteList.add (storedET);
                        }
                    }
                }
            }
        }

        ActionResult ar = ActionResult.createActionResult ().build ();
        try
        {
            expenseTypeDao.save (addOrEditList);
            expenseTypeDao.delete (deleteList);
            ar = ActionResult.ok ().build ();
        }
        catch (Exception e)
        {
            ar = ActionResult.serverError ().build ();
            logger.error (e.getMessage (), e);
        }

        return AjaxUtils.getJsonObject (ar);
    }
}
